package Network

import (
	"SQL/FSDB"
	"database/sql"
	"logs"
)

const (
	MsgTypeFriend = 1
	MsgTypeGroup  = 2
)

// ServerMsg 服务端发送到客户端的消息
// - Type:消息类型：1.用户消息 2.群消息
// - Content:消息具体内容
type ServerMsg struct {
	Type        int         `json:"Type"`
	ContentType string      `json:"ContentType"`
	Content     interface{} `json:"Content"`
}

type FriendMsg struct {
	FriendID   string `json:"FriendID"`
	FriendName string `json:"FriendName"`
	FriendIcon string `json:"FriendIcon"`
	MsgID      string `json:"MsgID"`
	Msg        string `json:"Msg"`
	CreateTime string `json:"CreateTime"`
}

type GroupMsg struct {
	GroupID    string `json:"GroupID"`
	GroupName  string `json:"GroupName"`
	GroupIcon  string `json:"GroupIcon"`
	SenderID   string `json:"SenderID"`
	SenderName string `json:"SenderName"`
	SenderIcon string `json:"SenderIcon"`
	MsgID      string `json:"MsgID"`
	Msg        string `json:"Msg"`
	CreateTime string `json:"CreateTime"`
}

func sendTextMessage(clientID string, args interface{}) (response *ServerResponse) {

	var errCode = Success
	var errMsg = ""
	var res interface{}
	defer func() {
		response = &ServerResponse{
			Method:  "/sendTextMessage",
			Code:    errCode,
			Message: errMsg,
			Result:  res,
		}
	}()

	var ok = false
	var judger FSJudger
	if ok, errCode, errMsg, judger = initJudger(args); !ok {
		return
	}

	talkerID := ""
	if talkerID, ok = judger.stringValueOf("talkerID"); !ok {
		return
	}
	msgContent := ""
	if msgContent, ok = judger.stringValueOf("msgContent"); !ok {
		return
	}
	if ok, errCode, errMsg = isValidMsgContent(msgContent); !ok {
		return
	}
	talkerIsUser := false
	if talkerIsUser, ok = judger.boolValueOf("talkerIsUser"); !ok {
		errCode = errInvalidBoolArg
		errMsg = "talkerIsUser参数有误！" + mInvalidBoolArg
		return
	}
	userID := clientID
	var resultMap map[string]string
	if talkerIsUser {
		if ok, errCode, errMsg = isExistTalkerID(userID, talkerID, true); !ok {
			return
		}
		errCode, errMsg, resultMap = writeTextMsgToDB(userID, talkerID, talkerIsUser, msgContent)
		if errCode == Success {
			writeResponseToClient(talkerID, &ServerResponse{
				Method:  "/receiveMessage",
				Code:    Success,
				Message: "新消息！",
				Result: ServerMsg{
					Type:        MsgTypeFriend,
					ContentType: "text",
					Content: FriendMsg{
						FriendID:   userID,
						FriendName: resultMap["SenderName"],
						FriendIcon: resultMap["SenderIcon"],
						MsgID:      resultMap["LastMsgID"],
						Msg:        msgContent,
						CreateTime: resultMap["CreateTime"],
					},
				},
			})
		}
	} else {
		if ok, errCode, errMsg = isExistTalkerID(userID, talkerID, false); !ok {
			return
		}
		errCode, errMsg, resultMap = writeTextMsgToDB(userID, talkerID, talkerIsUser, msgContent)
		if errCode == Success {
			writeResponseToGroup(userID, talkerID, resultMap["createTime"], ServerResponse{
				Method:  "/receiveMessage",
				Code:    Success,
				Message: "新消息！",
				Result: ServerMsg{
					Type:        MsgTypeGroup,
					ContentType: "text",
					Content: GroupMsg{
						GroupID:    talkerID,
						GroupName:  resultMap["GroupName"],
						GroupIcon:  resultMap["GroupIcon"],
						SenderName: resultMap["SenderName"],
						SenderIcon: resultMap["SenderIcon"],
						MsgID:      resultMap["LastMsgID"],
						Msg:        msgContent,
						CreateTime: resultMap["CreateTime"],
					},
				},
			})
		}
	}
	res = map[string]string{"MsgID": resultMap["LastMsgID"], "MsgCreateTime": resultMap["CreateTime"]}
	return
}

func writeTextMsgToDB(userID string, talkerID string, talkerIsUser bool, msgContent string) (errCode int, errMsg string, result map[string]string) {

	result = map[string]string{}
	msgInsertSQL := `INSERT INTO messages(sender,receiver,type,content)
					VALUES($1,$2,'text',$3)
					RETURNING id,createTime`
	tx, db, err := FSDB.BeginTx()
	if err != nil {
		errCode = errEndTx
		errMsg = "FSDB.BeginTx发生错误：" + err.Error()
		return
	}
	defer func() {
		if errCode == Success {
			tx.Commit()
		} else {
			tx.Rollback()
		}
		closeDB(db)
	}()

	miStmt, miRows, err := FSDB.QueryTx(tx, msgInsertSQL, userID, talkerID, msgContent)
	if err != nil {
		errCode = errEndTx
		errMsg = "FSDB.QueryTx msgInsertSQL发生错误：" + err.Error()
		return
	}
	defer miStmt.Close()
	defer miRows.Close()

	lastMsgID := ""
	msgCreateTime := ""
	for miRows.Next() {
		err = miRows.Scan(&lastMsgID, &msgCreateTime)
		if err != nil {
			errCode = errEndTx
			errMsg = "miRows.Scan发生错误：" + err.Error()
			return
		}
	}
	miRows.Close()

	result["LastMsgID"] = lastMsgID
	result["CreateTime"] = msgCreateTime

	sessionInsertSQL := ``
	if talkerIsUser {
		sessionInsertSQL = `SELECT updateUserSession($1,$2,$3);`
	} else {
		sessionInsertSQL = `SELECT updateGroupSession($1,$2,$3);`
	}
	_, err = FSDB.ExecTx(tx, sessionInsertSQL, userID, talkerID, lastMsgID)
	if err != nil {
		errCode = errEndTx
		errMsg = "FSDB.ExecTx sessionInsertSQL发生错误：" + err.Error()
		return
	}

	senderName := ""
	senderIcon := ""
	errCode, errMsg, senderName, senderIcon = objectInfoFromDBInContext(tx, userID)
	if errCode != Success {
		return
	}
	result["SenderName"] = senderName
	result["SenderIcon"] = senderIcon

	if !talkerIsUser {
		groupName := ""
		groupIcon := ""
		errCode, errMsg, groupName, groupIcon = objectInfoFromDBInContext(tx, talkerID)
		if errCode != Success {
			return
		}
		result["GroupName"] = groupName
		result["GroupIcon"] = groupIcon
	}

	// // 更新此客户端用户的在线时间
	// err = updateUserOnlineTime(tx, userID, msgCreateTime)
	// if err != nil {
	// 	errCode = errEndTx
	// 	errMsg = "updateUserOnlineTime 执行错误：" + err.Error()
	// 	return
	// }
	return Success, "发送成功！", result
}

// 获取资料
func objectInfoFromDBInContext(tx *sql.Tx, ID string) (errCode int, errMsg string, name string, icon string) {

	errCode = Success
	senderInfoSQL := `
				SELECT nickname,iconURL FROM objects WHERE id = $1;
				`
	siStmt, siRows, err := FSDB.QueryTx(tx, senderInfoSQL, ID)
	if err != nil {
		errCode = errDBQueryFailed
		errMsg = "objectInfoFromDB QueryTx执行错误，"
		logs.Print(errMsg, err.Error())
		return
	}
	defer siStmt.Close()
	defer siRows.Close()

	for siRows.Next() {
		err = siRows.Scan(&name, &icon)
		if err != nil {
			errCode = errRowsScan
			errMsg = "siRows.Scan执行错误，"
			logs.Print(errMsg, err.Error())
			return
		}
	}
	return
}
